package com.tianquan.miracle.beans;

import com.tianquan.miracle.annotation.Autowired;
import com.tianquan.miracle.conditional.ParseConditionPostProcessor;
import com.tianquan.miracle.core.RegisterBean;
import com.tianquan.miracle.postprocessor.BeanPostProcessor;
import com.tianquan.miracle.postprocessor.InitializingBean;
import com.tianquan.miracle.postprocessor.InjectBeanPostProcessor;
import com.tianquan.miracle.util.MiracleUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Bean注册器
 * 用于管理Bean的定义、创建和生命周期处理
 *
 * @author 天权
 */
public abstract class AbstractBeanRegister extends AbstractCommonBeanProcessor implements RegisterBean {

    /**
     * 一级缓存，用于存储已创建的Bean实例
     */
    private final Map<String, Object> beanCache = new HashMap<>();

    /**
     * 二级缓存，用于存储部分创建过程中的Bean实例
     */
    private final Map<String, Object> secondCache = new HashMap<>();

    /**
     * 存储Bean的定义信息
     */
    private final Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();

    @Override
    public void registerBean(String name, Object bean) {
        // 将创建的Bean实例注册到一级缓存中
        beanCache.put(name, bean);
    }

    /**
     * 加载所有Bean定义，并创建对应的Bean实例
     */
    public void loadBean() {
        for (String beanName : beanDefinitionMap.keySet()) {
            getSingletonBean(beanName);
        }
    }

    /**
     * 根据Bean名称获取Bean实例
     * 首先尝试从一级缓存中获取，如果获取不到则尝试从二级缓存中获取
     * 如果都获取不到，则创建一个新的Bean实例
     *
     * @param beanName Bean的名称
     * @return Bean实例
     */
    protected Object getSingletonBean(String beanName) {
        // 查询一级缓存
        Object bean = beanCache.get(beanName);
        if (bean != null) {
            return bean;
        }
        // 查询二级缓存
        if ((bean = secondCache.get(beanName)) != null) {
            return bean;
        }
        // 缓存中都也没有，则创建bean
        return createBean(beanName);
    }

    /**
     * 根据Class类型获取Bean实例
     * 首先尝试从一级缓存中获取，如果获取不到则尝试从二级缓存中获取
     * 如果都获取不到，则创建一个新的Bean实例
     *
     * @param aClass Bean的Class类型
     * @param <T>    Bean的类型参数
     * @return Bean实例
     */
    protected <T> T getSingletonBean(Class<T> aClass) {
        // 查询一级缓存
        for (Map.Entry<String, Object> stringObjectEntry : beanCache.entrySet()) {
            Object bean = stringObjectEntry.getValue();
            if (MiracleUtils.isRelatedTo(bean.getClass(), aClass)) {
                return (T) bean;
            }
        }
        // 查询二级缓存
        for (Map.Entry<String, Object> stringObjectEntry : secondCache.entrySet()) {
            Object bean = stringObjectEntry.getValue();
            if (MiracleUtils.isRelatedTo(bean.getClass(), aClass)) {
                return (T) bean;
            }
        }
        return (T) createBean(MiracleUtils.createBeanName(aClass));
    }

    /**
     * 创建Bean实例
     *
     * @param beanName Bean的名称
     * @return 创建的Bean实例
     */
    public Object createBean(String beanName) {
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if (beanDefinition == null) {
            return null;
        }
        // 实例化
        Object bean = instantiateBean(beanDefinition);
        // 放入二级缓存
        secondCache.put(beanName, bean);
        // 填充属性
        populateBean(bean);
        // 初始化
        bean = initializeBean(bean, beanName);
        // 放入一级缓存
        beanCache.put(beanName, bean);
        secondCache.remove(beanName);
        return bean;
    }

    /**
     * 实例化Bean
     *
     * @param beanDefinition Bean的定义信息
     * @return 实例化的Bean对象
     */
    public Object instantiateBean(BeanDefinition beanDefinition) {
        Class<?> beanClass = beanDefinition.getaClass();
        try {
            // 默认使用无参构造
            Constructor<?> constructor = beanClass.getConstructor();
            return constructor.newInstance();
        } catch (Exception e) {
            Constructor<?> agrsConstructor;
            // 如果没有无参构造，则使用有参构造
            Constructor<?>[] constructors = beanClass.getConstructors();
            // 有参构造大于1个就不知道用哪个,抛出异常
            if (constructors.length > 1) {
                throw new RuntimeException("beanClass has more than one constructor");
            }
            // 拿到有参构造
            agrsConstructor = constructors[0];
            // 拿到参数前面的注解
            Annotation[][] parameterAnnotations = agrsConstructor.getParameterAnnotations();
            // 拿到参数类型
            Class<?>[] parameterTypes = agrsConstructor.getParameterTypes();
            int length = parameterTypes.length;
            Object[] args = new Object[length];
            for (int i = 0; i < length; i++) {
                // 遍历每个参数的注解 判断参数前是否有@Autowired注解
                boolean isRequired = false;
                for (Annotation annotation : parameterAnnotations[i]) {
                    if (annotation instanceof Autowired autowired) {
                        if (autowired.required()) {
                            // 必要
                            args[i] = getSingletonBean(parameterTypes[i]);
                        } else {
                            // 判断容器里是否有需要的bean定义对象 没有就不注入
                            if (containsKey(MiracleUtils.createBeanName(parameterTypes[i]))) {
                                args[i] = getSingletonBean(parameterTypes[i]);
                            }
                        }
                        isRequired = true;
                    }
                }
                // 如果没有@Autowired注解，则默认从缓存中拿 没拿到就报错
                if (!isRequired) {
                    Object bean = getSingletonBean(parameterTypes[i]);
                    if (bean == null) {
                        throw new RuntimeException("beanClass has no Autowired annotation");
                    }
                    args[i] = bean;
                }
            }
            try {
                // 使用有参构造实例化对象
                return agrsConstructor.newInstance(args);
            } catch (Exception ex) {
                throw new RuntimeException(ex);
            }
        }
    }

    /**
     * 填充Bean属性
     *
     * @param bean Bean实例
     */
    public void populateBean(Object bean) {
        for (InjectBeanPostProcessor injectBeanPostProcessor : injectBeanPostProcessors) {
            injectBeanPostProcessor.inject(bean);
        }
        for (ParseConditionPostProcessor parseConditionPostProcessor : parseConditionPostProcessors) {
            parseConditionPostProcessor.parseCondition(bean);
        }
    }

    /**
     * 初始化Bean
     *
     * @param bean Bean实例
     * @param name Bean名称
     * @return 初始化后的Bean实例
     */
    public Object initializeBean(Object bean, String name) {
        // Aware接口
        invokeAwareMethods(bean, name);
        // Bean的前置初始化方法
        Object newBean = bean;
        if (bean != null) {
            newBean = applyBeanPostProcessorsBeforeInitialization(newBean, name);
        }
        // 初始化
        invokeInitMethods(newBean, name);
        // Bean的后置初始化方法
        if (newBean != null) {
            newBean = applyBeanPostProcessorsAfterInitialization(newBean, name);
        }
        // 是否有必要创建对象的代理类
        if (newBean != null) {
            return isNecessaryCreateProxy(newBean);
        }
        return newBean;
    }

    private Object applyBeanPostProcessorsBeforeInitialization(Object newBean, String beanName) {
        for (BeanPostProcessor beanPostProcessor : getBeanPostProcessors()) {
            newBean = beanPostProcessor.postProcessBeforeInitialization(newBean, beanName);
        }
        return newBean;
    }

    private Object applyBeanPostProcessorsAfterInitialization(Object newBean, String beanName) {
        for (BeanPostProcessor beanPostProcessor : getBeanPostProcessors()) {
            newBean = beanPostProcessor.postProcessBeforeInitialization(newBean, beanName);
        }
        return newBean;
    }

    private void invokeInitMethods(Object bean, String name) {
        if (bean instanceof InitializingBean initializingBean) {
            try {
                initializingBean.afterPropertiesSet();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    public abstract void invokeAwareMethods(Object bean, String name);

    /**
     * 注册Bean定义信息
     *
     * @param name           Bean名称
     * @param beanDefinition Bean定义信息
     */
    public void registerBeanDefinition(String name, BeanDefinition beanDefinition) {
        beanDefinitionMap.put(name, beanDefinition);
    }

    /**
     * 获取指定名称的Bean定义信息
     *
     * @param name Bean名称
     * @return Bean定义信息
     */
    public BeanDefinition getBeanDefinition(String name) {
        return beanDefinitionMap.get(name);
    }

    /**
     * 获取所有Bean定义信息
     *
     * @return 所有Bean定义信息列表
     */
    public List<BeanDefinition> getAllBeanDefinition() {
        return new ArrayList<>(beanDefinitionMap.values());
    }

    /**
     * 清除所有缓存
     */
    public void clean() {
        beanCache.clear();
        secondCache.clear();
        beanDefinitionMap.clear();
    }

    /**
     * 根据类型获取Bean实例列表
     *
     * @param beanClass Bean类型
     * @param <T>       Bean类型参数
     * @return Bean实例列表
     */
    @Override
    public <T> List<T> selectBean(Class<T> beanClass) {
        return beanCache.values().stream()
                .filter(bean -> beanClass.isAssignableFrom(bean.getClass()))
                .map(bean -> (T) bean)
                .collect(Collectors.toList());
    }

    /**
     * 判断缓存中是否包含指定类型的Bean
     *
     * @param aClass Bean类型
     * @return 如果缓存中包含指定类型的Bean则返回true，否则返回false
     */
    protected boolean containsValue(Class<?> aClass) {
        return beanCache.values().stream().map(Object::getClass).anyMatch(aClass::isAssignableFrom);
    }

    /**
     * 判断缓存中是否包含指定名称的Bean定义
     *
     * @param name Bean名称
     * @return 如果缓存中包含指定名称的Bean定义则返回true，否则返回false
     */
    protected boolean containsKey(String name) {
        return beanDefinitionMap.containsKey(name);
    }

}
